import json
from datetime import datetime
import bcrypt
from django.contrib.sessions.models import Session
from django.core.cache import cache
from django.core.paginator import Paginator
from django.db import connection
from django.http import JsonResponse
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.parsers import MultiPartParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.settings import api_settings
from rest_framework_simplejwt.tokens import RefreshToken
from djangoProject import settings
from menu.models import SysMenu, SysMenuSerializer
from role.models import SysRole
from user.models import SysUser, SysUserSerializer


# Create your views here.
class TestView(View):
    def get(self, request):
        # 获取 Redis 连接
        redis_conn = get_redis_connection("chain_info")

        # 存储数据
        redis_conn.set("name", "icy_hope")

        # 获取数据并打印
        name = redis_conn.get("name")
        print(name)  # 输出: b'icy_hope'

        # 如果你想以字符串形式打印
        print(name.decode('utf-8'))

        return JsonResponse({'status': 200, 'info': '测试！'})


class JwtTestView(View):
    def get(self, request):
        user = SysUser.objects.get(username='marry', password='123456')
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER  # 小写快捷键ctrl+shift+U
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        # 将用户对象传递进去，获取到该对象的属性值
        payload = jwt_payload_handler(user)
        # 将属性值编码成jwt格式的字符串
        token = jwt_encode_handler(payload)
        return JsonResponse({'status': 200, 'token': token})


# 登录
class LoginView(View):
    # 构造菜单树
    def buildTreeMenu(self, sysMenuList):
        resultMenuList: list[SysMenu] = list()
        for menu in sysMenuList:
            # 遍历子节点
            for e in sysMenuList:
                if e.parent_id == menu.id:
                    if not hasattr(menu, "children"):
                        menu.children = list()
                    menu.children.append(e)
            # 判断父节点，添加到集合中
            if menu.parent_id == 0:
                resultMenuList.append(menu)
        return resultMenuList

    # 生成token
    @staticmethod
    def get_tokens_for_user(user):
        refresh = RefreshToken.for_user(user)
        return {
            'refresh': str(refresh),
            'access': str(refresh.access_token),
        }

    def post(self, request):

        # print('request.session', request.session.get('is_login'))
        # if request.session.get('is_login'):  # 防止重复登录
        #     return JsonResponse({'status': 500, 'info': '已经登录'})

        if request.method == 'POST':
            # 处理表单提交逻辑
            data = json.loads(request.body)
            username = data.get('username')
            password = data.get('password')
            uuid = data.get('uuid')
            ImageCaptcha = data.get('ImageCaptcha')
            print(request.body, username, password)
            try:

                # 查询用户信息
                # user = authenticate(username=username, password=password)
                # user = SysUser.objects.get(username=username, password=password)
                if not ImageCaptcha:
                    return JsonResponse({'status': 400, 'info': '请输入验证码'})
                user = SysUser.objects.get(username=username)
                print('user', user)
                if user is None:
                    return JsonResponse({'status': 404, 'info': '未找到该用户'})
                # 获取数据库中的加密密码
                hashed_password = user.password
                print('hashed_password', hashed_password, password,
                      bcrypt.checkpw('1234567'.encode(),
                                     '$2a$11$5V69fDDTRSflQ.r4NjtT.u8MtjT.147Cc8jwkOWrV0juz.qYBTn1m'.encode()))

                # 使用 bcrypt 验证密码
                # is_correct = check_password('1234567', '$2a$11$5V69fDDTRSflQ.r4NjtT.u8MtjT.147Cc8jwkOWrV0juz.qYBTn1m')
                # print(is_correct, 'is_correct')

                if not bcrypt.checkpw(password.encode('utf-8'), hashed_password.encode('utf-8')):
                    return JsonResponse({'status': 500, 'info': '用户名或者密码错误1'})
                redis_client_captcha = get_redis_connection('img_code')  # 获取redis客户端

                # 5.写入redis(是字符串)
                # .setex('ImageCaptcha:' + uuid, 60 * 5, text)
                # 2. 从 Redis 中获取存储的验证码
                stored_code = redis_client_captcha.get('ImageCaptcha:' + uuid).decode('utf-8')
                print('uuid', stored_code)
                # 3. 验证验证码
                if not stored_code:
                    return JsonResponse({'status': 400, 'info': '验证码已过期'})
                if ImageCaptcha.lower() != stored_code.lower():
                    return JsonResponse({'status': 400, 'info': '验证码错误'})

                # 读取会话数据
                redis_client_session = get_redis_connection('session')  # 获取redis客户端
                # 检查 Redis 中是否有该用户的登录记录

                # 检查是否已经存在与该用户关联的会话
                # 未用redis只用session中可以这样实现防止重复登录
                # all_sessions = Session.objects.filter(expire_date__gte=timezone.now())
                # for session in all_sessions:
                #     # 强制登出之前的会话
                #     session_data = session.get_decoded()
                #     print('1111request.session', session_data, user.id)
                #     if session_data.get('_auth_user_id') == str(user.id):
                #         print('22222request.session', session_data.get('_auth_user_id'), user.id)
                #         # 强制登出之前的会话
                #         # session.flush()  # 将session中的所有内容全部清空
                #         session.delete()
                #         #     session.delete()
                #         break
                # login(request, user)


                # if sessionId == session_key:

                # 往session字典内写入用户状态和数据
                request.session['is_login'] = True
                request.session['user_id'] = user.id
                request.session['user_name'] = user.username
                # 生成sessionId
                # if not request.session.session_key:
                request.session.save()

                test_value = request.session.get('user_name', 'default_value')
                sessionId = request.session.session_key
                request.session['sessionId'] = sessionId
                request.session['uuid'] = uuid

                # session_key = redis_client_session.get('session:' + user.id)
                # if session_key is None:

                redis_client_session.set('session:' + str(user.id), sessionId)
                print('1231243')
                # 2. 从 Redis 中获取存储的验证码
                # stored_code = redis_client_captcha.get('ImageCaptcha:' + uuid).decode('utf-8')
                # redis_client_session.setex('session:' + uuid, 60 * 60, sessionId)
                print('request.session.session_key', sessionId, test_value)

                # 根据用户信息生成token
                # jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
                # jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
                # payload = jwt_payload_handler(user)
                # token = jwt_encode_handler(payload)

                # 生成 token
                # 签发token
                refresh = TokenObtainPairSerializer.get_token(user)
                access_token = str(refresh.access_token)
                refresh_token = str(refresh)

                # tokens = self.get_tokens_for_user(user)
                # access_token = tokens['access']
                # refresh_token = tokens['refresh']
                # 获取用户权限列表

                roleList = SysRole.objects.raw(
                    "SELECT id,name FROM sys_role WHERE id IN (SELECT role_id FROM sys_user_role WHERE user_id=" + str(
                        user.id) + ")")
                roles = ",".join([role.name for role in roleList])

                # 每个用户有多个权限，排除重复权限菜单
                menuSet: set[SysMenu] = set()
                for row in roleList:
                    menuList = SysMenu.objects.raw(
                        "SELECT * FROM sys_menu WHERE id IN(SELECT menu_id FROM sys_role_menu WHERE role_id=" + str(
                            row.id) + ")")
                    for row2 in menuList:
                        menuSet.add(row2)
                menuList: list[SysMenu] = list(menuSet)
                # sorted_menuList = sorted(menuList)
                sorted_menuList = menuSet
                # 构造菜单树
                sysMenuList: list[SysMenu] = self.buildTreeMenu(sorted_menuList)
                serializerMenuList = list()
                for sysMenu in sysMenuList:
                    serializerMenuList.append(SysMenuSerializer(sysMenu).data)
            except Exception as e:
                return JsonResponse({'status': 500, 'info': '用户名或者密码错误2'})

            # 手动设置cookie
            # response = JsonResponse(
            #     {'status': 200, 'access_token': access_token, 'refresh_token': refresh_token,
            #      'user': SysUserSerializer(user).data, 'info': '登录成功',
            #      'roles': roles,
            #      'menuList': serializerMenuList}
            # )
            # 手动设置cookie
            # response.set_cookie('sessionId', sessionId, max_age=3600, httponly=True, secure=True)
            # return response
            return JsonResponse(
                {'status': 200, 'access_token': access_token, 'refresh_token': refresh_token,
                 'user': SysUserSerializer(user).data, 'info': '登录成功',
                 'roles': roles,
                 'menuList': serializerMenuList})
        else:
            # 处理GET请求逻辑
            print('get')


# 退出登录
class logoutView(View):
    def post(self, request):
        if not request.session.get('is_login', None):  # 如果本来就未登录，也就没有登出一说
            return JsonResponse({'status': 200, 'info': '退出登录成功'}, status=200)
        print('退出登录')
        request.session.flush()  # 将session中的所有内容全部清空
        return JsonResponse({'status': 200, 'info': '退出登录成功'}, status=200)


# 刷新token
class tokenRefreshView(APIView):
    def post(self, request, *args, **kwargs):
        # 从请求中获取刷新令牌
        refresh_token = request.data.get('refresh')

        if not refresh_token:
            return Response({'error': 'Refresh token is required.'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 解码并验证刷新令牌
            refresh = RefreshToken(refresh_token)
            # 生成新的访问令牌
            new_access_token = str(refresh.access_token)
            # 返回新的访问令牌
            return Response({'access_token': new_access_token}, status=status.HTTP_200_OK)
        except (TokenError, InvalidToken) as e:
            # 如果令牌无效或解码失败，返回错误
            error_message = {
                'code': 'token_not_valid111',
                'detail': 'Given token not valid for any token type',
                'messages': [
                    {
                        'token_class': 'AccessToken',
                        'token_type': 'access',
                        'message': 'Token is invalid or expired'
                    }
                ]
            }
            return Response(error_message, status=status.HTTP_403_UNAUTHORIZED)
    # if not refresh_token:
    #         return Response({'error': '缺少刷新令牌'}, status=400)
    #     try:
    #         token = RefreshToken(refresh_token)
    #     except Exception as e:
    #         return Response({'error':'无效的刷新令牌'},status=400)
    #     if token.blacklisted:
    #         return Response({'error': '刷新令牌已被拉黑'}, status=403)
    #     refreshed_token = token.refresh()
    #
    #     return Response({
    #         'access': str(refreshed_token.access_token),
    #         'refresh': str(refreshed_token),
    #     }, status=status.HTTP_200_OK)


# 修改密码
class PwdView(View):
    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        id = data['id']
        oldPassword = data['oldPassword']
        newPassword = data['newPassword']
        obj_user = SysUser.objects.get(id=id)
        if obj_user.password == oldPassword:
            obj_user.password = newPassword
            obj_user.update_time = datetime.now().date()
            obj_user.save()
            return JsonResponse({'status': 200})
        else:
            return JsonResponse({'status': 500, 'errorInfo': '原密码错误!'})


# 获取用户信息
class GetUserInfo(View):
    def post(self, request):
        data = json.loads(request.body)
        userId = data.get('userId')
        # 验证 userId 是否存在
        if userId is None:
            return JsonResponse({'status': '400', 'error': 'userId parameter is required'})
        try:
            userInfo = SysUser.objects.raw("SELECT * FROM sys_user WHERE id = %s", [userId])
            # userInfo =  SysUser.objects.filter(id=id)
            if not userInfo:
                return JsonResponse({'status': '404', 'error': 'User not found'})
            # SysUser.objects.raw需要手动构造序列化器所需的JSON格式的数据

            # serialized_data = []
            # for user in userInfo:
            #     serialized_data.append({
            #         'id': user.id,
            #         'username': user.username,
            #         'email': user.email,
            #         'avatar': user.avatar,
            #         'phonenumber': user.phonenumber,
            #         # 添加其他需要的字段
            #
            #     })
            # 确保我们只处理一个用户对象
            user = None
            for u in userInfo:
                user = u
                break  # 因为我们只期望一个用户记录，所以可以直接退出循环
            serialized_data = {
                'id': user.id,
                'username': user.username,
                'email': user.email,
                'avatar': user.avatar,
                'phonenumber': user.phonenumber,
                # 添加其他需要的字段
            }
            #     filter和all可以SysUserSerializer(userInfo).data自动序列化
            # print(SysUserSerializer(userInfo).data)
            return JsonResponse({'status': '200', 'userInfo': serialized_data})
        except Exception as e:
            # 记录日志并返回错误信息
            return JsonResponse({'status': '500', 'error': str(e)})


# 查询用户列表
class SearchView(View):
    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        pageNum = data.get('pageNum')
        pageSize = data.get('pageSize')
        query = data['query']  # 查询参数
        # userListPage = Paginator(SysUser.objects.raw("SELECT * from sys_user"), pageSize).page(pageNum)
        # username__icontains 查询方法，模糊查询
        userListPage = Paginator(SysUser.objects.filter(username__icontains=query), pageSize).page(pageNum)
        print(userListPage)
        obj_users = userListPage.object_list.values()  # SysUser.objects.all/filter()需要.object_list.values()转成字典
        users = list(obj_users)  # 把外层的容器转为List
        # 手动将 RawQuerySet 转换为字典列表
        # obj_users = list(userListPage.object_list.values_list('id', 'username'))
        #
        # # 将值元组转换为字典
        # users = [{'id': user[0], 'username': user[1]} for user in obj_users]
        # users = []
        # for user in userListPage.object_list:
        #     user_data = {
        #         'id': user.id,
        #         'username': user.username
        #     }
        #     users.append(user_data)
        for user in users:
            userId = user['id']
            roleList = SysRole.objects.raw(
                "SELECT id,NAME FROM sys_role WHERE id IN (SELECT role_id FROM sys_user_role WHERE user_id=" + str(
                    userId) + ")")
            roleListDict = []
            for role in roleList:
                roleDict = {}
                roleDict['id'] = role.id
                roleDict['name'] = role.name
                roleListDict.append(roleDict)
            user['roleList'] = roleListDict
        total = SysUser.objects.filter(username__icontains=query).count()

        return JsonResponse({'status': 200, 'userList': users, 'total': total})


# 头像上传
class ImageView(View):
    parser_classes = [MultiPartParser]

    def post(self, request):
        print('上传')
        print(request.FILES)
        # file_obj = request.data['file']
        file = request.FILES.get('avatar')
        # file = request.POST.get('avatar')
        print("file", file)
        if file:
            file_name = file.name
            suffixName = file_name[file_name.rfind("."):]
            new_file_name = datetime.now().strftime('%Y%m%d%H%M%S') + suffixName
            file_path = str(settings.MEDIA_ROOT) + "\\userAvatar\\" + new_file_name
            print("file_path:", file_path)
            try:
                with open(file_path, 'wb') as f:
                    for chunk in file.chunks():
                        f.write(chunk)
                return JsonResponse({'status': 200, 'title': new_file_name})
            except:
                return JsonResponse({'status': 500, 'errorInfo': '上传头像失败'})
        return JsonResponse({'status': 404, 'errorInfo': '未找到图片'})


# 更换头像
class AvatarView(View):
    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        id = data['id']
        avatar = data['avatar']
        try:
            obj_user = SysUser.objects.get(id=id)
            obj_user.avatar = avatar
            obj_user.save()
            return JsonResponse({'status': 200})
        except SysUser.DoesNotExist:
            return JsonResponse({'status': 404, 'errorInfo': '未找到用户信息'})


# 新增修改用户
class saveUserView(View):
    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        id = data.get('id')
        print(id, data.get('username'))
        username = data.get('username')
        password = data.get('password')
        email = data.get('email')
        phonenumber = data.get('phonenumber')
        status = data.get('status')
        remark = data.get('remark')
        avatar = data.get('avatar')  # 假设默认头像路径为 'default.jpg'
        if id == -1:
            # 新增
            obj_sysUser = SysUser(
                username=username,
                password=password,
                email=email,
                phonenumber=phonenumber,
                status=status,
                remark=remark
            )
            obj_sysUser.create_time = datetime.now().date()
            obj_sysUser.avatar = 'default.jpg'
            obj_sysUser.password = "123456"  # 假设默认密码为 '123456'
            obj_sysUser.save()
        else:
            update_time = datetime.now().date()
            with connection.cursor() as cursor:
                cursor.execute(
                    """
                    UPDATE sys_user 
                    SET username = %s, 
                        email = %s, 
                        phonenumber = %s, 
                        status = %s, 
                        avatar = %s, 
                        remark = %s,
                        update_time = %s 
                    WHERE id = %s
                    """,
                    [username, email, phonenumber, status, avatar, remark, update_time, id]
                )
        return JsonResponse({'status': 200})


# 验证用户名是否重复
class CheckView(View):
    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        username = data.get('username')
        if SysUser.objects.filter(username=username).exists():
            return JsonResponse({'status': 500, 'msg': '用户名已存在!'})
        return JsonResponse({'status': 200})


# 删除用户
class deleteView(View):
    def delete(self, request):
        data = json.loads(request.body.decode("utf-8"))
        idList = data.get('ids')
        # orm
        # SysUserRole.objects.filter(user_id__in=idList).delete()
        # SysUser.objects.filter(id__in=idList).delete()
        # 原生
        with connection.cursor() as cursor:
            for id in idList:
                cursor.execute(
                    """
                    DELETE 
                    FROM sys_user_role
                    WHERE user_id = %s
                    """,
                    [id]
                )
                cursor.execute(
                    """
                    DELETE 
                    FROM sys_user
                    WHERE id = %s    
                    """,
                    [id]
                )
        return JsonResponse({'status': 200})
